package org.smth.search.indexer.impl;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexDeletionPolicy;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.smth.search.config.IndexerConfig;
import org.smth.search.indexer.IndexAnalyzer;
import org.smth.search.indexer.Indexer;
import org.smth.search.pojos.OnePost;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

@Singleton
public class IndexerImpl implements Indexer, IndexDeletionPolicy {

	@Inject
	private IndexerConfig config;

	@Inject
	private IndexAnalyzer analyzer;

	private IndexWriter writer;

	private int max;

	private DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");

	public IndexWriter getIndexWriter() {
		if (writer == null) {
			synchronized (this) {
				if (writer == null) {
					String path = config.getIndexFilePath();
					File file = new File(path);
					if (!file.exists()) {
						file.mkdirs();
					}
					if (!file.exists() || !file.isDirectory()) {
						throw new RuntimeException("路径:" + path + "错误");
					}
					File lock = new File(file, "write.lock");
					if (lock.exists()) {
						lock.delete();
					}
					try {
						File[] files = file.listFiles();
						if (files != null && files.length > 0) {
							IndexReader reader = IndexReader.open(file);
							int num = reader.numDocs();
							if (num > 0) {
								max = Integer.parseInt(reader.document(num - 1).get("postId"));
							} else {
								max = 0;
							}
							reader.close();
						} else {
							max = 0;
						}
						Directory directory = FSDirectory.getDirectory(file);
						writer = new IndexWriter(directory, true, analyzer);
						writer.setInfoStream(System.out);
						writer.setMaxFieldLength(config.getMaxFieldLength());
						writer.setMergeFactor(config.getMergeFactor());
						writer.setMaxBufferedDocs(config.getMergeFactor());
					} catch (IOException e) {
						throw new RuntimeException(e);
					}
				}
			}
		}
		return writer;
	}

	private void addField(Document document, String field, String content, Field.Store store, Field.Index index,
			Field.TermVector tv) {
		addField(document, field, content, store, index, tv, false);
	}

	private void addField(Document document, String field, String content, Field.Store store, Field.Index index,
			Field.TermVector tv, boolean lower) {
		if (content != null) {
			if (lower) {
				content = content.toLowerCase();
			}
			if (!"postId".equals(field)) {
				store = Field.Store.NO;
			}
			if (!(Field.Store.NO.equals(store) && Field.Index.NO.equals(index) && Field.TermVector.NO.equals(tv))) {
				document.add(new Field(field, content, store, index, tv));
			}
		}
	}

	public void indexPost(OnePost post) {
		IndexWriter writer = getIndexWriter();
		Document document = new Document();

		addField(document, "postId", String.valueOf(post.getPostId()), Field.Store.YES, Field.Index.NO, Field.TermVector.NO); //结果要用 不查找

		addField(document, "id", String.valueOf(post.getId()), Field.Store.YES, Field.Index.NO, Field.TermVector.NO); //结果要用  不查找
		addField(document, "firstId", String.valueOf(post.getFirstId()), Field.Store.YES, Field.Index.NO, Field.TermVector.NO); //结果要用  不查找
		addField(document, "reId", String.valueOf(post.getReId()), Field.Store.YES, Field.Index.NO, Field.TermVector.NO); //结果要用 不查找

		addField(document, "board", post.getBoardName(), Field.Store.YES, Field.Index.UN_TOKENIZED, Field.TermVector.NO, true);//结果要用  要查找 整体匹配
		addField(document, "author", post.getAuthor(), Field.Store.YES, Field.Index.UN_TOKENIZED, Field.TermVector.NO, true); //结果要用  要查找 整体匹配
		//addField(document,"postTime",post.getPostTime(),Field.Store.YES,Field.Index.TOKENIZED,Field.TermVector.NO);             //结果要用 要查找 部分匹配 找到即可
		addField(document, "time", format.format(post.getTime()), Field.Store.YES, Field.Index.UN_TOKENIZED, Field.TermVector.NO); //结果要用  要查找 整体匹配
		String s = String.valueOf(post.getSize());
		s = String.valueOf(s.length()) + s;
		addField(document, "size", s, Field.Store.YES, Field.Index.UN_TOKENIZED, Field.TermVector.NO); //结果要用  要查找 整体匹配
		addField(document, "flag", post.getFlag(), Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.NO); //结果要用  要查找 分开

		addField(document, "title", post.getTitle(), Field.Store.NO, Field.Index.TOKENIZED, Field.TermVector.YES); //结果不用  要查找 按关键词 有权重

		//addField(document,"content",post.getContent(),Field.Store.NO,Field.Index.TOKENIZED,Field.TermVector.YES);                 //结果不用  要查找 按关键词 有权重
		addField(document, "main", post.getMainContent(), Field.Store.NO, Field.Index.TOKENIZED, Field.TermVector.YES); //结果不用  要查找 按关键词 有权重
		addField(document, "post", post.getPostContent(), Field.Store.NO, Field.Index.TOKENIZED, Field.TermVector.YES); //结果不用  要查找 按关键词 有权重
		addField(document, "sign", post.getSign(), Field.Store.NO, Field.Index.TOKENIZED, Field.TermVector.YES); //结果不用  要查找 按关键词 有权重

		addField(document, "ip", post.getFromIp(), Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.NO); //结果要用  要查找 分开
		//addField(document,"mat",post.getModifiedAt(),Field.Store.YES,Field.Index.TOKENIZED,Field.TermVector.NO);                    //结果要用  要查找 分开
		addField(document, "mby", post.getModifiedBy(), Field.Store.YES, Field.Index.UN_TOKENIZED, Field.TermVector.NO, true); //结果要用  要查找 整体匹配
		addField(document, "mip", post.getModifiedIp(), Field.Store.YES, Field.Index.TOKENIZED, Field.TermVector.NO); //结果要用  要查找 分开

		addField(document, "origin", post.getFirstId() == post.getId() ? "1" : "0", Field.Store.YES, Field.Index.UN_TOKENIZED, Field.TermVector.NO); //结果要用  要查找 整体匹配

		try {
			writer.addDocument(document);
			max = post.getPostId();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public int getMaxId() {
		if (getIndexWriter() != null) {
			return max;
		} else {
			return 0;
		}
	}

	public void close() {
		if (writer != null) {
			try {
				writer.flush();
				writer.close();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				writer = null;
			}
		}
	}

	public void onInit(List commits) throws IOException {
	}

	public void onCommit(List commits) throws IOException {
	}

}
